package com.xhrd.framework.dao.mybatis;

import java.io.Serializable;
import java.util.List;

import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import com.xhrd.framework.dao.BaseDAO;
import com.xhrd.framework.dao.IdGenerator;
import com.xhrd.framework.dao.domain.BaseEntity;
import com.xhrd.framework.utils.GenericsUtils;
import com.xhrd.framework.vo.Page;
import com.xhrd.framework.vo.SearchCondition;

@SuppressWarnings(value = { "unchecked", "unused" })
public class BaseMyBatisDAOImpl<T extends BaseEntity, ID extends Serializable> implements BaseDAO<T, Serializable> {

    private static final Logger logger = LoggerFactory.getLogger(BaseMyBatisDAOImpl.class);

    /**
     * 数据操作访问模板对象
     */
    @Autowired(required = false)
    protected SqlSessionTemplate sqlSessionTemplate = null;

    public SqlSessionTemplate getSqlSessionTemplate() {
        return this.sqlSessionTemplate;
    }

    public String getMapperNamesapce() {
        StringBuilder mapperNamesapce = new StringBuilder();
        String simpleName = getClass().getPackage().getName().toString();
        mapperNamesapce.append(simpleName.substring(0, simpleName.lastIndexOf(".")));
        mapperNamesapce.append(".mapper.");
        Class<?> entityClass = GenericsUtils.getSuperClassGenricType(getClass());
        mapperNamesapce.append(entityClass.getSimpleName());
        mapperNamesapce.append("Mapper");
        return mapperNamesapce.toString();
    }

    @Override
    public T findById(Serializable id) {
        return getSqlSessionTemplate().selectOne(getMapperNamesapce() + ".getById", id);
    }

    @Override
    public List<T> findByIds(Serializable... ids) {
        return getSqlSessionTemplate().selectList(getMapperNamesapce() + ".getByIds", ids);
    }

    @Override
    public List<T> findAll() {
        return getSqlSessionTemplate().selectList(getMapperNamesapce() + ".getAll");
    }

    @Override
    public T save(T entity) {

        Class<ID> idClass = GenericsUtils.getGenericClass(getClass(), 1);
        ID id;
        try {

            id = idClass.newInstance();
            if (id instanceof String) {
                id = (ID) IdGenerator.generateUUID();
            } else if (id instanceof Long) {
                id = (ID) IdGenerator.generateLongId();
            } else {
                id = (ID) IdGenerator.generateId();
            }

            if (entity.getId() == null || !StringUtils.hasText(entity.getId().toString())) {
                entity.setId(id);
            }
            int rowNumber = getSqlSessionTemplate().insert(getMapperNamesapce() + ".insert", entity);
            return rowNumber >= 0 ? entity : null;

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return null;

    }

    @Override
    public boolean[] save(T... entities) {
        getSqlSessionTemplate().insert(getMapperNamesapce() + ".insert", entities.clone());
        return null;
    }

    @Override
    public T update(T entity) {
        int rowNumber = getSqlSessionTemplate().update(getMapperNamesapce() + ".update", entity);
        return rowNumber >= 0 ? entity : null;
    }

    @Override
    public boolean remove(T entity) {
        int rowNumber = getSqlSessionTemplate().delete(getMapperNamesapce() + ".delete", entity);
        return rowNumber >= 0 ? true : false;
    }

    @Override
    public void remove(T... entities) {
        getSqlSessionTemplate().delete(getMapperNamesapce() + ".removeByIds", entities.clone());
    }

    @Override
    public boolean removeById(Serializable id) {
        int rowNumber = getSqlSessionTemplate().delete(getMapperNamesapce() + ".delete", id);
        return rowNumber >= 0 ? true : false;
    }

    @Override
    public boolean removeByIds(Serializable... ids) {
        int rowNumber = getSqlSessionTemplate().delete(getMapperNamesapce() + ".deleteByIds", ids);
        return rowNumber >= 0 ? true : false;
    }

    @Override
    public T searchUnique(SearchCondition searchCondition) {
        String tmpStatementName = getMapperNamesapce() + ".searchUnique";
        return sqlSessionTemplate.selectOne(tmpStatementName, searchCondition);
    }

    @Override
    public List<T> search(T entity) {
        String tmpStatementName = getMapperNamesapce() + ".search";
        return sqlSessionTemplate.selectList(tmpStatementName, entity);
    }

    @Override
    public List<T> search(SearchCondition searchCondition) {
        String tmpStatementName = getMapperNamesapce() + ".search";
        return sqlSessionTemplate.selectList(tmpStatementName, searchCondition);
    }

    public Page<T> pageQuery(String statementName, SearchCondition searchCondition) {
        String tmpStatementName = getMapperNamesapce() + "." + statementName;
        return pageQuery(tmpStatementName, tmpStatementName + "Count", searchCondition);
    }

    @SuppressWarnings({ "rawtypes" })
    public Page<T> pageQuery(String statementName, String countStatementName, SearchCondition searchCondition) {
        Number totalCount = (Number) sqlSessionTemplate.selectOne(countStatementName, searchCondition);
        if (totalCount == null || totalCount.longValue() <= 0) {
            return new Page(searchCondition, 0);
        }
        Page<T> page = new Page(searchCondition, totalCount.intValue());
        RowBounds bounds = new RowBounds(page.getFirstResult(), page.getPageSize());
        List<T> list = sqlSessionTemplate.selectList(statementName, searchCondition, bounds);
        page.setResult(list);
        return page;
    }

}
